/**
 * 
 */
package org.jenkon.collection;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jenkon.decorator.CollectionDecorator;

/**
 * @author Jens Konopka
 * 
 * @param <E> the type of the decorator {@link Collection}.
 */
public class ObservableCollection<E> extends CollectionDecorator<E> {

	private final List<CollectionObserver<E>> observers = new ArrayList<CollectionObserver<E>>();

	/**
	 * @param decorator the {@link Collection} to decorate
	 */
	public ObservableCollection(final Collection<E> decorator) {
		super(decorator);
	}

	/**
	 * @param observer add a {@link CollectionObserver}
	 */
	public void addObserver(final CollectionObserver<E> observer) {
		this.observers.add(observer);
	}

	/**
	 * @param observer remove a {@link CollectionObserver}
	 */
	public void removeObserver(final CollectionObserver<E> observer) {
		this.observers.remove(observer);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.commons.decorator.AbstractCollectionDecorator#add(java.lang.Object)
	 */
	@Override
	public boolean add(final E e) {
		final boolean result = super.add(e);
		if (result) {
			for (final CollectionObserver<E> observer : observers) {
				observer.add(e);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.commons.decorator.AbstractCollectionDecorator#addAll(java.util.Collection)
	 */
	@Override
	public boolean addAll(final Collection<? extends E> c) {
		final boolean result = super.addAll(c);
		if (result) {
			for (final CollectionObserver<E> observer : observers) {
				observer.add(c);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.commons.decorator.AbstractCollectionDecorator#remove(java.lang.Object)
	 */
	@Override
	public boolean remove(final Object o) {
		final boolean result = super.remove(o);
		if (result) {
			for (final CollectionObserver<E> observer : observers) {
				observer.remove(o);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.commons.decorator.AbstractCollectionDecorator#removeAll(java.util.Collection)
	 */
	@Override
	public boolean removeAll(final Collection<?> c) {
		final boolean result = super.removeAll(c);
		if (result) {
			for (final CollectionObserver<E> observer : observers) {
				observer.remove(c);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.commons.decorator.AbstractCollectionDecorator#clear()
	 */
	@Override
	public void clear() {
		super.clear();
		for (final CollectionObserver<E> observer : observers) {
			observer.clear();
		}
	}

	/**
	 * Observer for {@link CollectionObserver}.
	 * 
	 * @author Jens Konopka
	 * 
	 * @param <E> the type of value
	 */
	public interface CollectionObserver<E> extends Serializable {

		/**
		 * This method is calling after the {@link Collection#add(Object)}.
		 * 
		 * @param e the value to add
		 */
		void add(final E e);

		/**
		 * This method is calling after the {@link Collection#remove(Object)}.
		 * 
		 * @param e the value to remove
		 */
		void remove(final Object e);

		/**
		 * This method is calling after the {@link Collection#addAll(Collection)}.
		 * 
		 * @param collection {@link Collection}
		 */
		void add(final Collection<? extends E> collection);

		/**
		 * This method is calling after the {@link Collection#removeAll(Collection)}.
		 * 
		 * @param c {@link Collection}
		 */
		void remove(final Collection<?> c);

		/**
		 * This method is calling after the {@link Collection#clear()}.
		 */
		void clear();

	}

}
